/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package dao;

import dao.exceptions.IllegalOrphanException;
import dao.exceptions.NonexistentEntityException;
import entities.Problem;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import entities.Contest;
import java.util.ArrayList;
import java.util.Collection;
import entities.KeyWord;
import entities.TestCase;
import entities.Submission;
import entities.ProblemStats;

/**
 *
 * @author santiagobaldrich
 */
public class ProblemJpaController {

    public ProblemJpaController()
    {
        emf = Persistence.createEntityManagerFactory("UNOJModelPU");
    }
    private EntityManagerFactory emf = null;

    public EntityManager getEntityManager()
    {
        return emf.createEntityManager();
    }

    public void create(Problem problem)
    {
        if (problem.getContestCollection() == null)
        {
            problem.setContestCollection(new ArrayList<Contest>());
        }
        if (problem.getKeyWordCollection() == null)
        {
            problem.setKeyWordCollection(new ArrayList<KeyWord>());
        }
        if (problem.getTestCaseCollection() == null)
        {
            problem.setTestCaseCollection(new ArrayList<TestCase>());
        }
        if (problem.getSubmissionCollection() == null)
        {
            problem.setSubmissionCollection(new ArrayList<Submission>());
        }
        if (problem.getProblemStatsCollection() == null)
        {
            problem.setProblemStatsCollection(new ArrayList<ProblemStats>());
        }
        EntityManager em = null;
        try
        {
            em = getEntityManager();
            em.getTransaction().begin();
            Collection<Contest> attachedContestCollection = new ArrayList<Contest>();
            for (Contest contestCollectionContestToAttach : problem.getContestCollection())
            {
                contestCollectionContestToAttach = em.getReference(contestCollectionContestToAttach.getClass(), contestCollectionContestToAttach.getIdContest());
                attachedContestCollection.add(contestCollectionContestToAttach);
            }
            problem.setContestCollection(attachedContestCollection);
            Collection<KeyWord> attachedKeyWordCollection = new ArrayList<KeyWord>();
            for (KeyWord keyWordCollectionKeyWordToAttach : problem.getKeyWordCollection())
            {
                keyWordCollectionKeyWordToAttach = em.getReference(keyWordCollectionKeyWordToAttach.getClass(), keyWordCollectionKeyWordToAttach.getIdKeyWord());
                attachedKeyWordCollection.add(keyWordCollectionKeyWordToAttach);
            }
            problem.setKeyWordCollection(attachedKeyWordCollection);
            Collection<TestCase> attachedTestCaseCollection = new ArrayList<TestCase>();
            for (TestCase testCaseCollectionTestCaseToAttach : problem.getTestCaseCollection())
            {
                testCaseCollectionTestCaseToAttach = em.getReference(testCaseCollectionTestCaseToAttach.getClass(), testCaseCollectionTestCaseToAttach.getIdTestCase());
                attachedTestCaseCollection.add(testCaseCollectionTestCaseToAttach);
            }
            problem.setTestCaseCollection(attachedTestCaseCollection);
            Collection<Submission> attachedSubmissionCollection = new ArrayList<Submission>();
            for (Submission submissionCollectionSubmissionToAttach : problem.getSubmissionCollection())
            {
                submissionCollectionSubmissionToAttach = em.getReference(submissionCollectionSubmissionToAttach.getClass(), submissionCollectionSubmissionToAttach.getIdSubmission());
                attachedSubmissionCollection.add(submissionCollectionSubmissionToAttach);
            }
            problem.setSubmissionCollection(attachedSubmissionCollection);
            Collection<ProblemStats> attachedProblemStatsCollection = new ArrayList<ProblemStats>();
            for (ProblemStats problemStatsCollectionProblemStatsToAttach : problem.getProblemStatsCollection())
            {
                problemStatsCollectionProblemStatsToAttach = em.getReference(problemStatsCollectionProblemStatsToAttach.getClass(), problemStatsCollectionProblemStatsToAttach.getIdProblemStats());
                attachedProblemStatsCollection.add(problemStatsCollectionProblemStatsToAttach);
            }
            problem.setProblemStatsCollection(attachedProblemStatsCollection);
            em.persist(problem);
            for (Contest contestCollectionContest : problem.getContestCollection())
            {
                contestCollectionContest.getProblemCollection().add(problem);
                contestCollectionContest = em.merge(contestCollectionContest);
            }
            for (KeyWord keyWordCollectionKeyWord : problem.getKeyWordCollection())
            {
                keyWordCollectionKeyWord.getProblemCollection().add(problem);
                keyWordCollectionKeyWord = em.merge(keyWordCollectionKeyWord);
            }
            for (TestCase testCaseCollectionTestCase : problem.getTestCaseCollection())
            {
                Problem oldProblemOfTestCaseCollectionTestCase = testCaseCollectionTestCase.getProblem();
                testCaseCollectionTestCase.setProblem(problem);
                testCaseCollectionTestCase = em.merge(testCaseCollectionTestCase);
                if (oldProblemOfTestCaseCollectionTestCase != null)
                {
                    oldProblemOfTestCaseCollectionTestCase.getTestCaseCollection().remove(testCaseCollectionTestCase);
                    oldProblemOfTestCaseCollectionTestCase = em.merge(oldProblemOfTestCaseCollectionTestCase);
                }
            }
            for (Submission submissionCollectionSubmission : problem.getSubmissionCollection())
            {
                Problem oldProblemOfSubmissionCollectionSubmission = submissionCollectionSubmission.getProblem();
                submissionCollectionSubmission.setProblem(problem);
                submissionCollectionSubmission = em.merge(submissionCollectionSubmission);
                if (oldProblemOfSubmissionCollectionSubmission != null)
                {
                    oldProblemOfSubmissionCollectionSubmission.getSubmissionCollection().remove(submissionCollectionSubmission);
                    oldProblemOfSubmissionCollectionSubmission = em.merge(oldProblemOfSubmissionCollectionSubmission);
                }
            }
            for (ProblemStats problemStatsCollectionProblemStats : problem.getProblemStatsCollection())
            {
                Problem oldProblemOfProblemStatsCollectionProblemStats = problemStatsCollectionProblemStats.getProblem();
                problemStatsCollectionProblemStats.setProblem(problem);
                problemStatsCollectionProblemStats = em.merge(problemStatsCollectionProblemStats);
                if (oldProblemOfProblemStatsCollectionProblemStats != null)
                {
                    oldProblemOfProblemStatsCollectionProblemStats.getProblemStatsCollection().remove(problemStatsCollectionProblemStats);
                    oldProblemOfProblemStatsCollectionProblemStats = em.merge(oldProblemOfProblemStatsCollectionProblemStats);
                }
            }
            em.getTransaction().commit();
        } finally
        {
            if (em != null)
            {
                em.close();
            }
        }
    }

    public void edit(Problem problem) throws IllegalOrphanException, NonexistentEntityException, Exception
    {
        EntityManager em = null;
        try
        {
            em = getEntityManager();
            em.getTransaction().begin();
            Problem persistentProblem = em.find(Problem.class, problem.getIdProblem());
            Collection<Contest> contestCollectionOld = persistentProblem.getContestCollection();
            Collection<Contest> contestCollectionNew = problem.getContestCollection();
            Collection<KeyWord> keyWordCollectionOld = persistentProblem.getKeyWordCollection();
            Collection<KeyWord> keyWordCollectionNew = problem.getKeyWordCollection();
            Collection<TestCase> testCaseCollectionOld = persistentProblem.getTestCaseCollection();
            Collection<TestCase> testCaseCollectionNew = problem.getTestCaseCollection();
            Collection<Submission> submissionCollectionOld = persistentProblem.getSubmissionCollection();
            Collection<Submission> submissionCollectionNew = problem.getSubmissionCollection();
            Collection<ProblemStats> problemStatsCollectionOld = persistentProblem.getProblemStatsCollection();
            Collection<ProblemStats> problemStatsCollectionNew = problem.getProblemStatsCollection();
            List<String> illegalOrphanMessages = null;
            for (TestCase testCaseCollectionOldTestCase : testCaseCollectionOld)
            {
                if (!testCaseCollectionNew.contains(testCaseCollectionOldTestCase))
                {
                    if (illegalOrphanMessages == null)
                    {
                        illegalOrphanMessages = new ArrayList<String>();
                    }
                    illegalOrphanMessages.add("You must retain TestCase " + testCaseCollectionOldTestCase + " since its problem field is not nullable.");
                }
            }
            for (Submission submissionCollectionOldSubmission : submissionCollectionOld)
            {
                if (!submissionCollectionNew.contains(submissionCollectionOldSubmission))
                {
                    if (illegalOrphanMessages == null)
                    {
                        illegalOrphanMessages = new ArrayList<String>();
                    }
                    illegalOrphanMessages.add("You must retain Submission " + submissionCollectionOldSubmission + " since its problem field is not nullable.");
                }
            }
            for (ProblemStats problemStatsCollectionOldProblemStats : problemStatsCollectionOld)
            {
                if (!problemStatsCollectionNew.contains(problemStatsCollectionOldProblemStats))
                {
                    if (illegalOrphanMessages == null)
                    {
                        illegalOrphanMessages = new ArrayList<String>();
                    }
                    illegalOrphanMessages.add("You must retain ProblemStats " + problemStatsCollectionOldProblemStats + " since its problem field is not nullable.");
                }
            }
            if (illegalOrphanMessages != null)
            {
                throw new IllegalOrphanException(illegalOrphanMessages);
            }
            Collection<Contest> attachedContestCollectionNew = new ArrayList<Contest>();
            for (Contest contestCollectionNewContestToAttach : contestCollectionNew)
            {
                contestCollectionNewContestToAttach = em.getReference(contestCollectionNewContestToAttach.getClass(), contestCollectionNewContestToAttach.getIdContest());
                attachedContestCollectionNew.add(contestCollectionNewContestToAttach);
            }
            contestCollectionNew = attachedContestCollectionNew;
            problem.setContestCollection(contestCollectionNew);
            Collection<KeyWord> attachedKeyWordCollectionNew = new ArrayList<KeyWord>();
            for (KeyWord keyWordCollectionNewKeyWordToAttach : keyWordCollectionNew)
            {
                keyWordCollectionNewKeyWordToAttach = em.getReference(keyWordCollectionNewKeyWordToAttach.getClass(), keyWordCollectionNewKeyWordToAttach.getIdKeyWord());
                attachedKeyWordCollectionNew.add(keyWordCollectionNewKeyWordToAttach);
            }
            keyWordCollectionNew = attachedKeyWordCollectionNew;
            problem.setKeyWordCollection(keyWordCollectionNew);
            Collection<TestCase> attachedTestCaseCollectionNew = new ArrayList<TestCase>();
            for (TestCase testCaseCollectionNewTestCaseToAttach : testCaseCollectionNew)
            {
                testCaseCollectionNewTestCaseToAttach = em.getReference(testCaseCollectionNewTestCaseToAttach.getClass(), testCaseCollectionNewTestCaseToAttach.getIdTestCase());
                attachedTestCaseCollectionNew.add(testCaseCollectionNewTestCaseToAttach);
            }
            testCaseCollectionNew = attachedTestCaseCollectionNew;
            problem.setTestCaseCollection(testCaseCollectionNew);
            Collection<Submission> attachedSubmissionCollectionNew = new ArrayList<Submission>();
            for (Submission submissionCollectionNewSubmissionToAttach : submissionCollectionNew)
            {
                submissionCollectionNewSubmissionToAttach = em.getReference(submissionCollectionNewSubmissionToAttach.getClass(), submissionCollectionNewSubmissionToAttach.getIdSubmission());
                attachedSubmissionCollectionNew.add(submissionCollectionNewSubmissionToAttach);
            }
            submissionCollectionNew = attachedSubmissionCollectionNew;
            problem.setSubmissionCollection(submissionCollectionNew);
            Collection<ProblemStats> attachedProblemStatsCollectionNew = new ArrayList<ProblemStats>();
            for (ProblemStats problemStatsCollectionNewProblemStatsToAttach : problemStatsCollectionNew)
            {
                problemStatsCollectionNewProblemStatsToAttach = em.getReference(problemStatsCollectionNewProblemStatsToAttach.getClass(), problemStatsCollectionNewProblemStatsToAttach.getIdProblemStats());
                attachedProblemStatsCollectionNew.add(problemStatsCollectionNewProblemStatsToAttach);
            }
            problemStatsCollectionNew = attachedProblemStatsCollectionNew;
            problem.setProblemStatsCollection(problemStatsCollectionNew);
            problem = em.merge(problem);
            for (Contest contestCollectionOldContest : contestCollectionOld)
            {
                if (!contestCollectionNew.contains(contestCollectionOldContest))
                {
                    contestCollectionOldContest.getProblemCollection().remove(problem);
                    contestCollectionOldContest = em.merge(contestCollectionOldContest);
                }
            }
            for (Contest contestCollectionNewContest : contestCollectionNew)
            {
                if (!contestCollectionOld.contains(contestCollectionNewContest))
                {
                    contestCollectionNewContest.getProblemCollection().add(problem);
                    contestCollectionNewContest = em.merge(contestCollectionNewContest);
                }
            }
            for (KeyWord keyWordCollectionOldKeyWord : keyWordCollectionOld)
            {
                if (!keyWordCollectionNew.contains(keyWordCollectionOldKeyWord))
                {
                    keyWordCollectionOldKeyWord.getProblemCollection().remove(problem);
                    keyWordCollectionOldKeyWord = em.merge(keyWordCollectionOldKeyWord);
                }
            }
            for (KeyWord keyWordCollectionNewKeyWord : keyWordCollectionNew)
            {
                if (!keyWordCollectionOld.contains(keyWordCollectionNewKeyWord))
                {
                    keyWordCollectionNewKeyWord.getProblemCollection().add(problem);
                    keyWordCollectionNewKeyWord = em.merge(keyWordCollectionNewKeyWord);
                }
            }
            for (TestCase testCaseCollectionNewTestCase : testCaseCollectionNew)
            {
                if (!testCaseCollectionOld.contains(testCaseCollectionNewTestCase))
                {
                    Problem oldProblemOfTestCaseCollectionNewTestCase = testCaseCollectionNewTestCase.getProblem();
                    testCaseCollectionNewTestCase.setProblem(problem);
                    testCaseCollectionNewTestCase = em.merge(testCaseCollectionNewTestCase);
                    if (oldProblemOfTestCaseCollectionNewTestCase != null && !oldProblemOfTestCaseCollectionNewTestCase.equals(problem))
                    {
                        oldProblemOfTestCaseCollectionNewTestCase.getTestCaseCollection().remove(testCaseCollectionNewTestCase);
                        oldProblemOfTestCaseCollectionNewTestCase = em.merge(oldProblemOfTestCaseCollectionNewTestCase);
                    }
                }
            }
            for (Submission submissionCollectionNewSubmission : submissionCollectionNew)
            {
                if (!submissionCollectionOld.contains(submissionCollectionNewSubmission))
                {
                    Problem oldProblemOfSubmissionCollectionNewSubmission = submissionCollectionNewSubmission.getProblem();
                    submissionCollectionNewSubmission.setProblem(problem);
                    submissionCollectionNewSubmission = em.merge(submissionCollectionNewSubmission);
                    if (oldProblemOfSubmissionCollectionNewSubmission != null && !oldProblemOfSubmissionCollectionNewSubmission.equals(problem))
                    {
                        oldProblemOfSubmissionCollectionNewSubmission.getSubmissionCollection().remove(submissionCollectionNewSubmission);
                        oldProblemOfSubmissionCollectionNewSubmission = em.merge(oldProblemOfSubmissionCollectionNewSubmission);
                    }
                }
            }
            for (ProblemStats problemStatsCollectionNewProblemStats : problemStatsCollectionNew)
            {
                if (!problemStatsCollectionOld.contains(problemStatsCollectionNewProblemStats))
                {
                    Problem oldProblemOfProblemStatsCollectionNewProblemStats = problemStatsCollectionNewProblemStats.getProblem();
                    problemStatsCollectionNewProblemStats.setProblem(problem);
                    problemStatsCollectionNewProblemStats = em.merge(problemStatsCollectionNewProblemStats);
                    if (oldProblemOfProblemStatsCollectionNewProblemStats != null && !oldProblemOfProblemStatsCollectionNewProblemStats.equals(problem))
                    {
                        oldProblemOfProblemStatsCollectionNewProblemStats.getProblemStatsCollection().remove(problemStatsCollectionNewProblemStats);
                        oldProblemOfProblemStatsCollectionNewProblemStats = em.merge(oldProblemOfProblemStatsCollectionNewProblemStats);
                    }
                }
            }
            em.getTransaction().commit();
        } catch (Exception ex)
        {
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0)
            {
                Integer id = problem.getIdProblem();
                if (findProblem(id) == null)
                {
                    throw new NonexistentEntityException("The problem with id " + id + " no longer exists.");
                }
            }
            throw ex;
        } finally
        {
            if (em != null)
            {
                em.close();
            }
        }
    }

    public void destroy(Integer id) throws IllegalOrphanException, NonexistentEntityException
    {
        EntityManager em = null;
        try
        {
            em = getEntityManager();
            em.getTransaction().begin();
            Problem problem;
            try
            {
                problem = em.getReference(Problem.class, id);
                problem.getIdProblem();
            } catch (EntityNotFoundException enfe)
            {
                throw new NonexistentEntityException("The problem with id " + id + " no longer exists.", enfe);
            }
            List<String> illegalOrphanMessages = null;
            Collection<TestCase> testCaseCollectionOrphanCheck = problem.getTestCaseCollection();
            for (TestCase testCaseCollectionOrphanCheckTestCase : testCaseCollectionOrphanCheck)
            {
                if (illegalOrphanMessages == null)
                {
                    illegalOrphanMessages = new ArrayList<String>();
                }
                illegalOrphanMessages.add("This Problem (" + problem + ") cannot be destroyed since the TestCase " + testCaseCollectionOrphanCheckTestCase + " in its testCaseCollection field has a non-nullable problem field.");
            }
            Collection<Submission> submissionCollectionOrphanCheck = problem.getSubmissionCollection();
            for (Submission submissionCollectionOrphanCheckSubmission : submissionCollectionOrphanCheck)
            {
                if (illegalOrphanMessages == null)
                {
                    illegalOrphanMessages = new ArrayList<String>();
                }
                illegalOrphanMessages.add("This Problem (" + problem + ") cannot be destroyed since the Submission " + submissionCollectionOrphanCheckSubmission + " in its submissionCollection field has a non-nullable problem field.");
            }
            Collection<ProblemStats> problemStatsCollectionOrphanCheck = problem.getProblemStatsCollection();
            for (ProblemStats problemStatsCollectionOrphanCheckProblemStats : problemStatsCollectionOrphanCheck)
            {
                if (illegalOrphanMessages == null)
                {
                    illegalOrphanMessages = new ArrayList<String>();
                }
                illegalOrphanMessages.add("This Problem (" + problem + ") cannot be destroyed since the ProblemStats " + problemStatsCollectionOrphanCheckProblemStats + " in its problemStatsCollection field has a non-nullable problem field.");
            }
            if (illegalOrphanMessages != null)
            {
                throw new IllegalOrphanException(illegalOrphanMessages);
            }
            Collection<Contest> contestCollection = problem.getContestCollection();
            for (Contest contestCollectionContest : contestCollection)
            {
                contestCollectionContest.getProblemCollection().remove(problem);
                contestCollectionContest = em.merge(contestCollectionContest);
            }
            Collection<KeyWord> keyWordCollection = problem.getKeyWordCollection();
            for (KeyWord keyWordCollectionKeyWord : keyWordCollection)
            {
                keyWordCollectionKeyWord.getProblemCollection().remove(problem);
                keyWordCollectionKeyWord = em.merge(keyWordCollectionKeyWord);
            }
            em.remove(problem);
            em.getTransaction().commit();
        } finally
        {
            if (em != null)
            {
                em.close();
            }
        }
    }

    public List<Problem> findProblemEntities()
    {
        return findProblemEntities(true, -1, -1);
    }

    public List<Problem> findProblemEntities(int maxResults, int firstResult)
    {
        return findProblemEntities(false, maxResults, firstResult);
    }

    private List<Problem> findProblemEntities(boolean all, int maxResults, int firstResult)
    {
        EntityManager em = getEntityManager();
        try
        {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            cq.select(cq.from(Problem.class));
            Query q = em.createQuery(cq);
            if (!all)
            {
                q.setMaxResults(maxResults);
                q.setFirstResult(firstResult);
            }
            return q.getResultList();
        } finally
        {
            em.close();
        }
    }

    public Problem findProblem(Integer id)
    {
        EntityManager em = getEntityManager();
        try
        {
            return em.find(Problem.class, id);
        } finally
        {
            em.close();
        }
    }

    public int getProblemCount()
    {
        EntityManager em = getEntityManager();
        try
        {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            Root<Problem> rt = cq.from(Problem.class);
            cq.select(em.getCriteriaBuilder().count(rt));
            Query q = em.createQuery(cq);
            return ((Long) q.getSingleResult()).intValue();
        } finally
        {
            em.close();
        }
    }

    public Problem getProblemByName(String name)
    {
        EntityManager em = null;
        Problem p = null;
        try
        {
            em = getEntityManager();
            Query q = em.createNamedQuery("Problem.findByName");
            q.setParameter("name", name);
            p = (Problem) q.getSingleResult();
        } catch (Exception e)
        {
            p = null;
        } finally
        {
            em.clear();
            em.close();
        }
        return p;
    }

    public List<Problem> findAll()
    {
        EntityManager em = null;
        try
        {
            em = getEntityManager();
            Query q = em.createNamedQuery("Problem.findAll");
            return q.getResultList();
        }
        catch (Exception e)
        {
            return null;
        }
    }
}
